#pragma once
#include <stack>
#include "DX11Includes.h"
#include "InputManager.h"
#include "ScreenManager.h"
#include "MeshFactory.h"
#include "AssetManagment.h"

struct BlendState
{
	ID3D11BlendState* State;
	float*			  BlendFactor;
	UINT			  Mask;
};

struct DepthStencilState
{
	ID3D11DepthStencilState*	State;
	UINT						StencilRef;
};

struct AntiAliasingSettings
{
	AntiAliasingSettings(bool minReq = true)
	{
		if(minReq)
		{
			multSampleEnable = false;
			surfaceFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
							
			sampleCount = 1;
			sampleQuality = 0;
		}
		else
		{	
			multSampleEnable = true;
			surfaceFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
							
			sampleCount = D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT;
			sampleQuality = 128; ///soh um numero grande
		}

	}

	AntiAliasingSettings(DXGI_FORMAT  format, bool multsample,UINT count, UINT quality)
	{
		multSampleEnable = multsample;
		sampleCount = count;
		sampleQuality = quality;
		surfaceFormat = format;
	}

	bool multSampleEnable;
	UINT sampleCount;
	UINT sampleQuality;
	DXGI_FORMAT surfaceFormat;
};

class RenderTarget;

class EngineStuff
{
public:
	EngineStuff(void);
	~EngineStuff(void);
	void InitEngine(const char* appName, HINSTANCE hInstance , int width, int height, bool fullscreen, bool vsyncEnabled,D3D_FEATURE_LEVEL featureLevel =  D3D_FEATURE_LEVEL_10_0 , D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_HARDWARE, AntiAliasingSettings set = AntiAliasingSettings() );
	void EnterOnLoop();
	void AddScreen(IScreen* screen) {screenManager->AddScreen(screen); } 
	void RemoveScreen(IScreen* screen) {screenManager->RemoveScreen(screen); } 
	void ActiveScreen(IScreen* screen) {screenManager->ActiveScreen(screen); } 		
	AntiAliasingSettings CheckMultSample(AntiAliasingSettings setting);
	HRESULT RecreateDevice(UINT width, UINT height, D3D_FEATURE_LEVEL featureLevel , D3D_DRIVER_TYPE driverType , AntiAliasingSettings set );

	static void PushDepthState(ID3D11DepthStencilState* state,UINT stencilRef) 
	{
		DepthStencilState ds;
		ds.State = state;
		ds.StencilRef = stencilRef;
		EImediateDeviceContext->OMSetDepthStencilState(state, stencilRef);
		DepthStencilStates.push(ds);
	}

	static DepthStencilState  PopDepthState() 
	{
		DepthStencilStates.pop();
		DepthStencilState resp = DepthStencilStates.top();		
		EImediateDeviceContext->OMSetDepthStencilState(resp.State,resp.StencilRef);
		return resp;		
	}

	static void PushRasterState(ID3D11RasterizerState* state) 
	{
		EImediateDeviceContext->RSSetState( state);
		RasterizerStates.push(state);
	}

	static ID3D11RasterizerState* PopRasterState() 
	{
		RasterizerStates.pop();
		ID3D11RasterizerState* resp = RasterizerStates.top();		
		EImediateDeviceContext->RSSetState(RasterizerStates.top());
		return resp;		
	}

	static void PushBlenderState(ID3D11BlendState* state,float blendFactor[], UINT sampleMasK) 
	{
		BlendState bs;
		bs.BlendFactor = &blendFactor[0];
		bs.Mask = sampleMasK;
		bs.State = state;
		EImediateDeviceContext->OMSetBlendState( state,blendFactor,sampleMasK);
		BlendStates.push(bs);
	}

	static BlendState PopBlenderState() 
	{
		BlendStates.pop();
		BlendState resp = BlendStates.top();		
		EImediateDeviceContext->OMSetBlendState( resp.State,resp.BlendFactor,resp.Mask);
		return resp;		
	}
	
	static void PushRenderTarget(RenderTarget* rt);	
	static RenderTarget* PopRenderTarget(void);
	
	static int						g_WindowWidth;
	static int						g_WindowHeight;	
	static ID3D11Device*			EGraphicsDevice; 	
	static InputManager*			EInputManager;
	static AssetManagment*			EAssetManagment;

	static ID3D11DeviceContext*		EImediateDeviceContext;
	ID3D11DepthStencilState*		g_pDepthStencilState;    
	ID3D11RasterizerState*			g_pRasterState;
	ID3D11BlendState*				g_pAlphaBlendState;    
	ID3D11DepthStencilView*			g_pDepthStencilView;
	ID3D11RenderTargetView*			g_pSCRenderTargetView ; 	
	D3D11_VIEWPORT					ViewPort;				
	
private:
	HINSTANCE				hInstance;
	WNDCLASSEX				wClasseX;
	HWND					hWnd;	
	bool					fullscreen;
	bool					m_vsync_enabled;		
	IDXGISwapChain*         g_pSwapChain ;
	DWORD					elapsedTime;
	ScreenManager*			screenManager;
	UINT					numerator;
	UINT					denominator;
	float					ClearColor[4];				
	static stack<DepthStencilState>			DepthStencilStates;
	static stack<ID3D11RasterizerState*>	RasterizerStates;
	static stack<BlendState>				BlendStates;
	static stack<RenderTarget*>				RenderTargets;

	static LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
	void InitWindow(const char* appName);
	int MessageLoop();
	HRESULT InitDirectX11(D3D_FEATURE_LEVEL featureLevel, D3D_DRIVER_TYPE driverType , AntiAliasingSettings set  );
	void Cleanup();
	void RenderLoop();	
};
